package com.stylefeng.guns.modular.assessment.calculate;

import com.stylefeng.guns.common.persistence.model.Assessment;
import com.stylefeng.guns.common.persistence.model.Indication;
import com.stylefeng.guns.core.util.DoubleUtil;
import com.stylefeng.guns.modular.indication.service.IIndicationService;
import org.beetl.core.statement.nat.NativeArrayNode;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.Date;
import java.util.List;

import static java.util.stream.Collectors.toList;

public abstract class FirstIndicationCalculator extends IndicationCalculator {

	@Autowired
	protected IIndicationService indicationService;

	public abstract List<SecondIndicationCalculator> getSecondIndicationCalculateList();


	@Override
	public Assessment get(Integer roadnetId, Date beginDate, Date endDate) {
		Assessment assessment = calculate(roadnetId, beginDate, endDate);
		setWarningLevel(assessment);
		return assessment;
	}

	private void setWarningLevel(Assessment assessment) {
		Double assessmentValue = assessment.getAssessmentValue();
		if (assessmentValue <= 0.3) {
			assessment.setWarningLevel(Assessment.WARNING_LEVEL_LOW);
		} else if (assessmentValue <= 0.9) {
			assessment.setWarningLevel(Assessment.WARNING_LEVEL_LOWER);
		} else if (assessmentValue < 1.5) {
			assessment.setWarningLevel(Assessment.WARNING_LEVEL_MEDIUM);
		} else {
			assessment.setWarningLevel(Assessment.WARNING_LEVEL_HIGH);
		}
	}

	@Override
	public Assessment calculate(Integer roadnetId, Date beginDate, Date endDate) {
		List<Assessment> secondIndicationResults = getSecondIndicationResults(roadnetId, beginDate, endDate);

		Assessment firstIndicationResult = calculateFirstIndication(secondIndicationResults, roadnetId, beginDate,
				endDate);
		firstIndicationResult.setNexLvlList(secondIndicationResults);
		return firstIndicationResult;
	}

	private List<Assessment> getSecondIndicationResults(Integer roadnetId, Date beginDate, Date endDate) {
		return getSecondIndicationCalculateList().stream()
				.map(secondIndicationCalculator -> secondIndicationCalculator.get(roadnetId, beginDate, endDate))
				.collect(toList());
	}

	private Assessment calculateFirstIndication(List<Assessment> secondIndicationResults, Integer roadnetId,
			Date beginDate, Date endDate) {
		boolean isWaring = false;
		Double resultVal = 0D;
		for (int j = 0; j < secondIndicationResults.size(); j++) {
			Indication indication = indicationService.selectById(secondIndicationResults.get(j).getIndicationId());

			Double max = indication.getMaxVal();
			Double min = indication.getMinVal();

			//2级指标的值
			Assessment secondIndicationRes = secondIndicationResults.get(j);
			Double secondIndicationValue = secondIndicationRes.getAssessmentValue();
			if (secondIndicationRes.getWarningLevel() == 4 && isWaring == false)
				isWaring = true;

			if (secondIndicationValue == -1) {
				resultVal = Double.NaN;

			} else {
				//归一化处理
				double x = DoubleUtil.safeDiv(DoubleUtil.sub(secondIndicationValue, min), DoubleUtil.sub(max, min));

				//权重
				Double weight = indication.getWeight();
				//K
				Double k = 1.63;
				Double ux = DoubleUtil.mul(2, Math.pow(x, k));
				resultVal += DoubleUtil.mul(DoubleUtil.add(x, ux), DoubleUtil.div(weight, 2));
			}

		}
		Assessment result = genResult(resultVal, roadnetId, beginDate, endDate);
		if (isWaring) {
			result.setWarningLevel(4);
		} else {
			if (resultVal <= 0.3) {
				result.setWarningLevel(1);
			} else if (resultVal <= 0.9) {
				result.setWarningLevel(2);
			} else if (resultVal < 1.5) {
				result.setWarningLevel(3);
			} else {
				result.setWarningLevel(4);
			}
		}
		return result;
	}

}
